'use client';

import React, { useState, useCallback, useMemo, useRef, useEffect, memo, useDeferredValue } from 'react';
import { Card, Tag, Tooltip, Button, Space, Typography, Modal, message } from 'antd';
import { CalendarOutlined, ReloadOutlined, CopyOutlined } from '@ant-design/icons';
import type { Dayjs } from 'dayjs';
import { RoleType, InstrumentScheduleSpecificDate, InstrumentScheduleTimeslot, DateType } from '@/types/instrument';
import { ScheduleType } from '@/types/system';

// 用户级别颜色映射
const getUserLevelColor = (roleType: RoleType, isSelected: boolean = false, displayMode: any = 'single') => {
  if (isSelected) {
    return '#ff7875'; // 选中时统一使用红色
  }

  // 所有用户模式使用统一颜色
  if (displayMode === 'all') {
    return '#edf1ff'; // 统一的浅蓝色
  }

  // 单个用户模式使用不同颜色（用于色卡显示）
  switch (roleType) {
    case RoleType.LEVEL_1_USER:
      return '#add8e6'; // 1级用户：浅蓝色
    case RoleType.LEVEL_2_USER:
      return '#ffdab9'; // 2级用户：浅橙色
    case RoleType.LEVEL_3_USER:
      return '#dda0dd'; // 3级用户：浅紫色
    default:
      return '#edf1ff'; // 默认颜色
  }
};
import { DisplayForType } from './index';

const { Text } = Typography;

// 日期状态接口
interface DayStatus {
  date: string;
  scheduleType: ScheduleType; // 1=节假日 2=调休日 3=正常周末
  isWorkday: boolean; // 是否为工作日
}

interface CalendarViewProps {
  weekDates: Array<{ date: string; dayName: string; dayNumber: number; dayObj: Dayjs }>;
  dayStatusMap: Map<string, DayStatus>;
  getSpecificDateConfig: (date: string) => InstrumentScheduleSpecificDate | undefined;
  generateDefaultTimeslots: (date: string) => InstrumentScheduleTimeslot[];
  minDuration: number;
  readOnly: boolean;
  selectedDate: string;
  setSelectedDate: (date: string) => void;
  onSpecificDateChange?: (specificDates: InstrumentScheduleSpecificDate[]) => void;
  specificDates: InstrumentScheduleSpecificDate[];
  displayFor: DisplayForType;
  convertToSpecificTimeslots: (timeslots: InstrumentScheduleTimeslot[]) => Array<{ startTime: string; endTime: string }>;
}

const CalendarView: React.FC<CalendarViewProps> = ({
  weekDates,
  dayStatusMap,
  getSpecificDateConfig,
  generateDefaultTimeslots,
  minDuration,
  readOnly,
  selectedDate,
  setSelectedDate,
  onSpecificDateChange,
  specificDates,
  displayFor,
  convertToSpecificTimeslots,
}) => {
  const dragContainerRef = useRef<HTMLDivElement>(null);
  const [isDragging, setIsDragging] = useState(false);
  const [dragData, setDragData] = useState<{
    startDate: string;
    startTime: number;
    endDate: string;
    endTime: number;
  } | null>(null);
  const [previewData, setPreviewData] = useState<{
    startDate: string;
    startTime: number;
    endDate: string;
    endTime: number;
  } | null>(null);
  const [mousePosition, setMousePosition] = useState<{
    x: number;
    y: number;
  } | null>(null);
  const [selectedSlot, setSelectedSlot] = useState<{
    id: string;
    date: string;
    startTime: number;
    endTime: number;
    source: 'specific' | 'default';
    specificIndex?: number;
  } | null>(null);
  const [isEditingSlot, setIsEditingSlot] = useState(false);
  const [resizeMode, setResizeMode] = useState<'none' | 'top' | 'bottom'>('none');
  const [originalSlotData, setOriginalSlotData] = useState<{
    startTime: number;
    endTime: number;
  } | null>(null);
  const [contextMenu, setContextMenu] = useState<{
    visible: boolean;
    x: number;
    y: number;
    slot?: {
      id: string;
      date: string;
      startTime: number;
      endTime: number;
      source: 'specific' | 'default';
      specificIndex?: number;
    };
  }>({ visible: false, x: 0, y: 0 });

  // 新增一个工具函数，获取大于等于minDuration的最小15的倍数
  function getMinStep(minDuration: number) {
    return Math.ceil(minDuration / 15) * 15;
  }

  // 在组件内部，计算实际最小步长
  const minStep = getMinStep(minDuration);



  // 时间转换函数
  const timeStringToMinutes = useCallback((timeString: string) => {
    const [hour, minute] = timeString.split(':').map(Number);
    return hour * 60 + minute;
  }, []);

  const minutesToTimeString = useCallback((minutes: number) => {
    const hour = Math.floor(minutes / 60);
    const minute = minutes % 60;
    return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}:00`;
  }, []);

  // 校验时间段是否符合最小间隔要求
  const validateTimeSlotInterval = useCallback((startTime: number, endTime: number) => {
    const duration = endTime - startTime;

    // 检查时长是否满足最小要求
    if (duration < minDuration) {
      message.error(`时间段长度不能少于${minDuration}分钟`);
      return false;
    }

    // 如果设置了30分钟最小间隔，检查时间点是否符合要求
    if (minDuration >= 30) {
      // 检查开始时间是否为30分钟的倍数（从00:00开始计算）
      if (startTime % 30 !== 0) {
        const nextValidStart = Math.ceil(startTime / 30) * 30;
        const nextValidStartTime = minutesToTimeString(nextValidStart).substring(0, 5);
        message.error(`开始时间必须为30分钟的倍数，建议调整为${nextValidStartTime}`);
        return false;
      }

      // 检查结束时间是否为30分钟的倍数
      if (endTime % 30 !== 0) {
        const nextValidEnd = Math.ceil(endTime / 30) * 30;
        const nextValidEndTime = minutesToTimeString(nextValidEnd).substring(0, 5);
        message.error(`结束时间必须为30分钟的倍数，建议调整为${nextValidEndTime}`);
        return false;
      }

      // 检查时长是否为30分钟的倍数
      if (duration % 30 !== 0) {
        message.error(`时间段长度必须为30分钟的倍数`);
        return false;
      }
    }

    return true;
  }, [minDuration, minutesToTimeString]);

  // 获取日期的所有时间段（优化缓存策略）
  const getDateTimeSlots = useMemo(() => {
    const cache = new Map<string, Array<{
      id: string;
      startTime: number;
      endTime: number;
      source: 'specific' | 'default';
      editable: boolean;
      specificIndex?: number;
      roleType?: RoleType;
    }>>();

    return (date: string) => {
      // 使用更精确的缓存键，包含displayFor和相关数据的哈希
      const cacheKey = `${date}-${displayFor}-${JSON.stringify(specificDates.filter(sd => sd.specificDate === date))}`;

      if (cache.has(cacheKey)) {
        return cache.get(cacheKey)!;
      }

      const specificConfig = getSpecificDateConfig(date);
      const slots: Array<{
        id: string;
        startTime: number;
        endTime: number;
        source: 'specific' | 'default';
        editable: boolean;
        specificIndex?: number;
        roleType?: RoleType;
      }> = [];

      // 简化逻辑：所有用户模式不叠加，使用统一显示
      if (displayFor === 'all') {
        // 优先显示1级用户的配置，如果没有则显示默认配置
        const level1Config = specificDates.find(
          sd => sd.specificDate === date && sd.roleType === RoleType.LEVEL_1_USER
        );

        if (level1Config && level1Config.dateType === DateType.CUSTOM_TIME_SLOTS) {
          level1Config.timeslots.forEach((slot, index) => {
            slots.push({
              id: `specific-${date}-${index}`,
              startTime: timeStringToMinutes(slot.startTime),
              endTime: timeStringToMinutes(slot.endTime),
              source: 'specific' as const,
              editable: true,
              specificIndex: index,
              roleType: RoleType.LEVEL_1_USER
            });
          });
        } else {
          // 显示默认时间段
          const defaultTimeslots = generateDefaultTimeslots(date);
          defaultTimeslots.forEach((slot, index) => {
            slots.push({
              id: `default-${date}-${index}`,
              startTime: timeStringToMinutes(slot.startTime),
              endTime: timeStringToMinutes(slot.endTime),
              source: 'default' as const,
              editable: false,
              roleType: RoleType.LEVEL_1_USER
            });
          });
        }
      } else {
        // 单个用户级别显示模式
        if (specificConfig && specificConfig.dateType === DateType.CUSTOM_TIME_SLOTS) {
          specificConfig.timeslots.forEach((slot, index) => {
            slots.push({
              id: `specific-${date}-${index}`,
              startTime: timeStringToMinutes(slot.startTime),
              endTime: timeStringToMinutes(slot.endTime),
              source: 'specific' as const,
              editable: true,
              specificIndex: index,
              roleType: specificConfig.roleType
            });
          });
        } else {
          // 默认配置的时间段
          const defaultTimeslots = generateDefaultTimeslots(date);
          defaultTimeslots.forEach((slot, index) => {
            slots.push({
              id: `default-${date}-${index}`,
              startTime: timeStringToMinutes(slot.startTime),
              endTime: timeStringToMinutes(slot.endTime),
              source: 'default' as const,
              editable: false,
              roleType: displayFor
            });
          });
        }
      }

      cache.set(cacheKey, slots);
      return slots;
    };
  }, [getSpecificDateConfig, timeStringToMinutes, generateDefaultTimeslots, specificDates, displayFor]);

  // 使用延迟值来优化displayFor切换时的性能
  const deferredDisplayFor = useDeferredValue(displayFor);

  // 预计算所有日期的时间段数据，避免在渲染时重复计算
  const allDateSlots = useMemo(() => {
    const slotsMap = new Map<string, ReturnType<typeof getDateTimeSlots>>();
    weekDates.forEach(dateInfo => {
      slotsMap.set(dateInfo.date, getDateTimeSlots(dateInfo.date));
    });
    return slotsMap;
  }, [weekDates, getDateTimeSlots]);

  // 根据鼠标位置计算时间和日期（优化版本）
  const getTimeAndDateFromPosition = useCallback((clientX: number, clientY: number) => {
    if (!dragContainerRef.current) return null;

    const container = dragContainerRef.current;
    const rect = container.getBoundingClientRect();

    // 计算相对位置
    const relativeX = clientX - rect.left;
    const relativeY = clientY - rect.top;

    // 计算列（日期）- 需要考虑时间列的宽度
    const timeColumnWidth = 80; // 时间列宽度
    const dateColumnWidth = (rect.width - timeColumnWidth) / 7;
    const dateIndex = Math.floor((relativeX - timeColumnWidth) / dateColumnWidth);

    // 计算精确的时间位置
    const headerHeight = 60; // 标题行高度
    const rowHeight = 60; // 每行高度

    // 计算精确的时间进度（包含小数部分）
    const timeProgress = (relativeY - headerHeight) / (24 * rowHeight);
    const totalMinutes = timeProgress * 24 * 60; // 从0:00开始的总分钟数

    // 根据最小间隔要求对齐时间
    const alignmentStep = minDuration >= 30 ? 30 : 15; // 30分钟最小间隔时对齐到30分钟，否则对齐到15分钟
    const alignedMinutes = Math.round(totalMinutes / alignmentStep) * alignmentStep;
    const time = Math.max(0, Math.min(1440, alignedMinutes)); // 限制在0:00-24:00之间

    const hour = Math.floor(time / 60);

    if (dateIndex < 0 || dateIndex >= 7 || time < 0 || time >= 1440) {
      return null;
    }

    return {
      dateIndex,
      time,
      hour
    };
  }, []);

  // 直接切换为自定义预约时间（移除弹窗确认）
  const switchToCustom = (_date: string, onSwitch: () => void) => {
    onSwitch();
  };

  // 处理点击默认配置时间段
  const handleDefaultSlotClick = useCallback((e: React.MouseEvent, slot: {
    id: string;
    startTime: number;
    endTime: number;
    source: 'specific' | 'default';
    specificIndex?: number;
  }, date: string) => {
    e.preventDefault();
    e.stopPropagation();
    console.log(slot.id,'id');
    
    if (readOnly || slot.source !== 'default' || !onSpecificDateChange) return;
    
    switchToCustom(date, () => {
      const updatedSpecificDates = [...specificDates];
      const existingIndex = updatedSpecificDates.findIndex(
        sd => sd.specificDate === date && (displayFor === 'all' ? sd.roleType === RoleType.LEVEL_1_USER : sd.roleType === displayFor)
      );
      
      if (existingIndex >= 0) {
        if (updatedSpecificDates[existingIndex].dateType === DateType.CLOSE_ALL_DAY) {
          updatedSpecificDates[existingIndex].dateType = DateType.CUSTOM_TIME_SLOTS;
          updatedSpecificDates[existingIndex].timeslots = convertToSpecificTimeslots(generateDefaultTimeslots(date));
        } else {
          message.info('当天已有特殊配置，可以直接编辑');
          return;
        }
      } else {
        updatedSpecificDates.push({
          roleType: displayFor === 'all' ? RoleType.LEVEL_1_USER : displayFor,
          specificDate: date,
          dateType: DateType.CUSTOM_TIME_SLOTS,
          timeslots: convertToSpecificTimeslots(generateDefaultTimeslots(date))
        });
      }
      
      onSpecificDateChange(updatedSpecificDates);
      setSelectedDate(date);
      message.success('已将默认配置转换为特殊配置');
    });
  }, [specificDates, displayFor, onSpecificDateChange, generateDefaultTimeslots, convertToSpecificTimeslots, readOnly, setSelectedDate]);

  // 修改现有的 handleSlotClick 函数，区分默认和特殊配置的点击处理
  const handleSlotClick = useCallback((e: React.MouseEvent, slot: {
    id: string;
    startTime: number;
    endTime: number;
    source: 'specific' | 'default';
    specificIndex?: number;
  }, date: string) => {
    e.preventDefault();
    e.stopPropagation();
    
    if (readOnly) return;
    
    if (slot.source === 'default') {
      // 处理默认配置时间段的点击
      handleDefaultSlotClick(e, slot, date);
      return;
    }
    
    // 选中特殊配置时间段
    setSelectedSlot({
      ...slot,
      date
    });
    setSelectedDate(date);
  }, [readOnly, setSelectedDate, handleDefaultSlotClick]);

  // 右键菜单处理
  const handleSlotContextMenu = useCallback((e: React.MouseEvent, slot: {
    id: string;
    startTime: number;
    endTime: number;
    source: 'specific' | 'default';
    specificIndex?: number;
  }, date: string) => {
    e.preventDefault();
    e.stopPropagation();
    
    if (readOnly || slot.source === 'default') return;
    
    setContextMenu({
      visible: true,
      x: e.clientX,
      y: e.clientY,
      slot: { ...slot, date }
    });
  }, [readOnly]);

  // 删除时间段（优化版本）
  const handleDeleteSlot = useCallback((slotToDelete?: {
    id: string;
    date: string;
    startTime: number;
    endTime: number;
    source: 'specific' | 'default';
    specificIndex?: number;
  }) => {
    const targetSlot = slotToDelete || selectedSlot;
    if (!targetSlot || !onSpecificDateChange || targetSlot.specificIndex === undefined) return;
    
    const updatedSpecificDates = [...specificDates];
    const existingIndex = updatedSpecificDates.findIndex(
      sd => sd.specificDate === targetSlot.date && (displayFor === 'all' ? sd.roleType === RoleType.LEVEL_1_USER : sd.roleType === displayFor)
    );
    
    if (existingIndex >= 0 && targetSlot.specificIndex < updatedSpecificDates[existingIndex].timeslots.length) {
      // 删除指定时间段
      updatedSpecificDates[existingIndex].timeslots.splice(targetSlot.specificIndex, 1);
      
      // 如果没有时间段了，保持配置但清空时间段
      if (updatedSpecificDates[existingIndex].timeslots.length === 0) {
        updatedSpecificDates[existingIndex].dateType = DateType.CLOSE_ALL_DAY;
      }
      
      onSpecificDateChange(updatedSpecificDates);
      setSelectedSlot(null);
      setContextMenu({ visible: false, x: 0, y: 0 });
    }
  }, [selectedSlot, specificDates, displayFor, onSpecificDateChange]);

  // 关闭右键菜单
  const handleCloseContextMenu = useCallback(() => {
    setContextMenu({ visible: false, x: 0, y: 0 });
  }, []);

  // 开始边框拖拽调整
  const handleStartResize = useCallback((e: React.MouseEvent, mode: 'top' | 'bottom') => {
    if (!selectedSlot || readOnly) return;
    
    e.preventDefault();
    e.stopPropagation();
    
    setResizeMode(mode);
    setIsEditingSlot(true);
    setIsDragging(true);
    setMousePosition({ x: e.clientX, y: e.clientY }); // 设置初始鼠标位置
    setOriginalSlotData({
      startTime: selectedSlot.startTime,
      endTime: selectedSlot.endTime
    });
    setDragData({
      startDate: selectedSlot.date,
      startTime: selectedSlot.startTime,
      endDate: selectedSlot.date,
      endTime: selectedSlot.endTime
    });
    setPreviewData({
      startDate: selectedSlot.date,
      startTime: selectedSlot.startTime,
      endDate: selectedSlot.date,
      endTime: selectedSlot.endTime
    });
    
    // 阻止文本选择
    document.body.style.userSelect = 'none';
  }, [selectedSlot, readOnly]);

  // 开始编辑拖拽
  const handleStartEditDrag = useCallback((e: React.MouseEvent) => {
    if (!selectedSlot || readOnly) return;
    
    e.preventDefault();
    e.stopPropagation();
    
    setResizeMode('none');
    setIsEditingSlot(true);
    setIsDragging(true);
    setMousePosition({ x: e.clientX, y: e.clientY }); // 设置初始鼠标位置
    setOriginalSlotData({
      startTime: selectedSlot.startTime,
      endTime: selectedSlot.endTime
    });
    setDragData({
      startDate: selectedSlot.date,
      startTime: selectedSlot.startTime,
      endDate: selectedSlot.date,
      endTime: selectedSlot.endTime
    });
    setPreviewData({
      startDate: selectedSlot.date,
      startTime: selectedSlot.startTime,
      endDate: selectedSlot.date,
      endTime: selectedSlot.endTime
    });
    
    // 阻止文本选择
    document.body.style.userSelect = 'none';
  }, [selectedSlot, readOnly]);

  // 修改 handleMouseDown，增加 confirmed 参数
  const handleMouseDown = useCallback((e: React.MouseEvent, dateIndex: number, hour: number, confirmed = false) => {
    if (readOnly) return;
    e.preventDefault();
    const date = weekDates[dateIndex].date;

    // 检查是否已选择日期，如果没有选择则先选择该日期
    if (selectedDate !== date) {
      setSelectedDate(date);
      return;
    }

    const specificConfig = getSpecificDateConfig(date);
    const defaultTimeslots = generateDefaultTimeslots(date);
    if (!confirmed && !specificConfig && defaultTimeslots.length > 0) {
      switchToCustom(date, () => {
        if (!onSpecificDateChange) return;
        const updatedSpecificDates = [...specificDates];
        updatedSpecificDates.push({
          roleType: displayFor === 'all' ? RoleType.LEVEL_1_USER : displayFor,
          specificDate: date,
          dateType: DateType.CUSTOM_TIME_SLOTS,
          timeslots: convertToSpecificTimeslots(defaultTimeslots)
        });
        onSpecificDateChange(updatedSpecificDates);
        // 递归调用自身，但传递 confirmed=true，避免再次弹窗
        setTimeout(() => handleMouseDown(e, dateIndex, hour, true), 0);
      });
      return;
    }
    // 计算精确的起始时间 - 基于鼠标在格子中的位置
    const rect = e.currentTarget.getBoundingClientRect();
    const relativeY = e.clientY - rect.top;
    const timeProgress = relativeY / rect.height;
    const minutesInHour = timeProgress * 60;
    const totalMinutes = hour * 60 + minutesInHour;
    // 根据最小间隔要求对齐时间
    const alignmentStep = minDuration >= 30 ? 30 : 15; // 30分钟最小间隔时对齐到30分钟，否则对齐到15分钟
    const alignedMinutes = Math.round(totalMinutes / alignmentStep) * alignmentStep;
    const startTime = Math.max(0, Math.min(1440 - minStep, alignedMinutes)); // 限制在0:00-24:00之间
    setIsDragging(true);
    setIsEditingSlot(false);
    setMousePosition({ x: e.clientX, y: e.clientY }); // 设置初始鼠标位置
    setDragData({
      startDate: date,
      startTime: startTime,
      endDate: date,
      endTime: startTime + minStep // 步长为minStep
    });
    setPreviewData({
      startDate: date,
      startTime: startTime,
      endDate: date,
      endTime: startTime + minStep
    });
    setSelectedDate(date);
    setSelectedSlot(null); // 清除选中的时间段
    // 阻止文本选择
    document.body.style.userSelect = 'none';
  }, [readOnly, weekDates, minStep, setSelectedDate, getSpecificDateConfig, generateDefaultTimeslots, onSpecificDateChange, specificDates, displayFor]);

  // 修改 handleMouseMove（优化版本）
  const handleMouseMove = useCallback((e: MouseEvent) => {
    if (!isDragging || !dragData) return;

    // 更新鼠标位置（用于视觉反馈）
    setMousePosition({ x: e.clientX, y: e.clientY });

    const position = getTimeAndDateFromPosition(e.clientX, e.clientY);
    if (!position) return;

    const endDate = weekDates[position.dateIndex].date;
    const currentTime = position.time; // 直接使用计算好的精确时间
    
    if (isEditingSlot && originalSlotData) {
      // 编辑模式：根据调整类型处理
      if (resizeMode === 'top') {
        // 调整开始时间
        const newStartTime = Math.min(currentTime, originalSlotData.endTime - minStep);
        setPreviewData({
          ...dragData,
          startTime: newStartTime,
          endTime: originalSlotData.endTime
        });
      } else if (resizeMode === 'bottom') {
        // 调整结束时间
        const newEndTime = Math.max(currentTime, originalSlotData.startTime + minStep);
        setPreviewData({
          ...dragData,
          startTime: originalSlotData.startTime,
          endTime: newEndTime
        });
      } else {
        // 整体移动
        const duration = originalSlotData.endTime - originalSlotData.startTime;
        const newStartTime = currentTime;
        const newEndTime = newStartTime + duration;
        
        // 确保不超出边界
        if (newEndTime <= 1440) {
          setPreviewData({
            ...dragData,
            startTime: newStartTime,
            endTime: newEndTime
          });
        }
      }
    } else {
      // 创建新时间段模式
      const finalEndTime = Math.max(currentTime, dragData.startTime + minStep);
      
      // 如果是同一天，直接设置结束时间
      if (endDate === dragData.startDate) {
        setPreviewData({
          ...dragData,
          endTime: finalEndTime
        });
      } else {
        // 跨天拖拽，暂时只支持同一天
        setPreviewData({
          ...dragData,
          endTime: dragData.startTime + minStep
        });
      }
    }
  }, [isDragging, dragData, weekDates, minStep, isEditingSlot, originalSlotData, resizeMode, getTimeAndDateFromPosition]);

  // 检查时间段是否重复
  const isTimeSlotOverlapping = useCallback((date: string, newStartTime: number, newEndTime: number, excludeIndex?: number) => {
    const existingSlots = getDateTimeSlots(date);
    
    for (let i = 0; i < existingSlots.length; i++) {
      const slot = existingSlots[i];
      
      // 如果是编辑模式，跳过当前编辑的时间段
      if (excludeIndex !== undefined && slot.specificIndex === excludeIndex) {
        continue;
      }
      
      // 检查时间段是否重叠
      if (newStartTime < slot.endTime && newEndTime > slot.startTime) {
        return true;
      }
    }
    
    return false;
  }, [getDateTimeSlots]);

  // 处理拖拽创建时间段
  const handleCreateTimeSlot = useCallback((date: string, startTime: number, endTime: number) => {
    if (!onSpecificDateChange) return;

    // 校验时间段间隔
    if (!validateTimeSlotInterval(startTime, endTime)) {
      return;
    }

    // 检查是否与现有时间段重叠
    if (isTimeSlotOverlapping(date, startTime, endTime)) {
      message.error('时间段重叠，无法创建');
      return;
    }

    const updatedSpecificDates = [...specificDates];
    const existingIndex = updatedSpecificDates.findIndex(
      sd => sd.specificDate === date && (displayFor === 'all' ? sd.roleType === RoleType.LEVEL_1_USER : sd.roleType === displayFor)
    );

    const newTimeslot = {
      startTime: minutesToTimeString(startTime),
      endTime: minutesToTimeString(endTime)
    };

    if (existingIndex >= 0) {
      // 更新现有配置
      if (updatedSpecificDates[existingIndex].dateType === DateType.CLOSE_ALL_DAY) {
        updatedSpecificDates[existingIndex].dateType = DateType.CUSTOM_TIME_SLOTS;
        updatedSpecificDates[existingIndex].timeslots = [newTimeslot];
      } else {
        updatedSpecificDates[existingIndex].timeslots.push(newTimeslot);
      }
    } else {
      // 创建新配置
      const defaultTimeslots = generateDefaultTimeslots(date);
      updatedSpecificDates.push({
        roleType: displayFor === 'all' ? RoleType.LEVEL_1_USER : displayFor,
        specificDate: date,
        dateType: DateType.CUSTOM_TIME_SLOTS,
        timeslots: [
          ...convertToSpecificTimeslots(defaultTimeslots),
          newTimeslot
        ]
      });
    }

    onSpecificDateChange(updatedSpecificDates);
  }, [specificDates, displayFor, minutesToTimeString, onSpecificDateChange, generateDefaultTimeslots, convertToSpecificTimeslots, isTimeSlotOverlapping, validateTimeSlotInterval]);

  // 处理编辑时间段
  const handleEditTimeSlot = useCallback((slot: {
    id: string;
    date: string;
    startTime: number;
    endTime: number;
    source: 'specific' | 'default';
    specificIndex?: number;
  }, newStartTime: number, newEndTime: number) => {
    if (!onSpecificDateChange || slot.specificIndex === undefined) return;

    // 校验时间段间隔
    if (!validateTimeSlotInterval(newStartTime, newEndTime)) {
      return;
    }

    // 检查编辑后的时间段是否与其他时间段重叠
    if (isTimeSlotOverlapping(slot.date, newStartTime, newEndTime, slot.specificIndex)) {
      message.error('时间段重叠，无法编辑');
      return;
    }

    const updatedSpecificDates = [...specificDates];
    const existingIndex = updatedSpecificDates.findIndex(
      sd => sd.specificDate === slot.date && (displayFor === 'all' ? sd.roleType === RoleType.LEVEL_1_USER : sd.roleType === displayFor)
    );

    if (existingIndex >= 0 && slot.specificIndex < updatedSpecificDates[existingIndex].timeslots.length) {
      updatedSpecificDates[existingIndex].timeslots[slot.specificIndex] = {
        startTime: minutesToTimeString(newStartTime),
        endTime: minutesToTimeString(newEndTime)
      };
      onSpecificDateChange(updatedSpecificDates);
      
      // 更新选中的时间段信息
      setSelectedSlot({
        ...slot,
        startTime: newStartTime,
        endTime: newEndTime
      });
    }
  }, [specificDates, displayFor, minutesToTimeString, onSpecificDateChange, isTimeSlotOverlapping, validateTimeSlotInterval]);

  // 结束拖拽
  const handleMouseUp = useCallback(() => {
    if (!isDragging || !dragData || !previewData) return;
    
    setIsDragging(false);
    
    if (isEditingSlot && selectedSlot) {
      // 编辑现有时间段
      handleEditTimeSlot(selectedSlot, previewData.startTime, previewData.endTime);
    } else {
      // 创建新时间段
      handleCreateTimeSlot(previewData.startDate, previewData.startTime, previewData.endTime);
    }
    
    setDragData(null);
    setPreviewData(null);
    setIsEditingSlot(false);
    setResizeMode('none');
    setOriginalSlotData(null);
    setMousePosition(null); // 清除鼠标位置

    // 恢复文本选择
    document.body.style.userSelect = '';
  }, [isDragging, dragData, previewData, isEditingSlot, selectedSlot, handleEditTimeSlot, handleCreateTimeSlot]);

  // 绑定全局鼠标事件（优化版本）
  useEffect(() => {
    if (isDragging) {
      // 使用更高频率的节流来提高响应性
      let lastCall = 0;
      const handleMouseMoveThrottled = (e: MouseEvent) => {
        // 减少节流延迟，提高跟随精度
        if (Date.now() - lastCall < 8) {
          return; // 约120fps，更流畅的跟随
        }
        lastCall = Date.now();
        handleMouseMove(e);
      };

      document.addEventListener('mousemove', handleMouseMoveThrottled, { passive: false });
      document.addEventListener('mouseup', handleMouseUp, { passive: false });
      
      return () => {
        document.removeEventListener('mousemove', handleMouseMoveThrottled);
        document.removeEventListener('mouseup', handleMouseUp);
      };
    }
  }, [isDragging, handleMouseMove, handleMouseUp]);

  // 监听点击外部关闭右键菜单
  useEffect(() => {
    const handleClickOutside = () => {
      if (contextMenu.visible) {
        setContextMenu({ visible: false, x: 0, y: 0 });
      }
    };

    if (contextMenu.visible) {
      document.addEventListener('click', handleClickOutside);
      return () => document.removeEventListener('click', handleClickOutside);
    }
  }, [contextMenu.visible]);

  // 处理重置状态
  const handleReset = useCallback(() => {
    if (!onSpecificDateChange) return;
    
    Modal.confirm({
      title: '确认重置',
      content: '确定要重置所有特定日期配置吗？这将恢复到默认配置状态。',
      okText: '确认',
      cancelText: '取消',
      onOk: () => {
        // 清空所有特定日期配置
        onSpecificDateChange([]);
        setSelectedSlot(null);
      }
    });
  }, [onSpecificDateChange]);

  return (
    <Card>
      <div style={{ marginBottom: 16, display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
          <CalendarOutlined />
          <Text strong>日历拖拽模式</Text>
          <Text type="secondary">
            按住鼠标拖拽选择时间段，最小时长 {minDuration} 分钟
            。请切换到特定用户下修改预约时段
          </Text>
        </div>
        
        {!readOnly && (
          <Space>
            <Button 
              icon={<ReloadOutlined />} 
              onClick={handleReset}
              type="default"
              size="small"
            >
              重置配置
            </Button>
          </Space>
        )}
      </div>

      {/* 色卡标记 */}
      <div style={{ marginBottom: 16, display: 'flex', alignItems: 'center', gap: 16, flexWrap: 'wrap' }}>
        <Text strong style={{ fontSize: '12px' }}>颜色说明：</Text>
        <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
          <div style={{
            width: 16,
            height: 16,
            backgroundColor: getUserLevelColor(RoleType.LEVEL_1_USER, false, 'single'),
            borderRadius: '2px',
            border: '1px solid #d9d9d9'
          }}></div>
          <Text style={{ fontSize: '12px' }}>1级用户可预约时间</Text>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
          <div style={{
            width: 16,
            height: 16,
            backgroundColor: getUserLevelColor(RoleType.LEVEL_2_USER, false, 'single'),
            borderRadius: '2px',
            border: '1px solid #d9d9d9'
          }}></div>
          <Text style={{ fontSize: '12px' }}>2级用户可预约时间</Text>
        </div>
        <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
          <div style={{
            width: 16,
            height: 16,
            backgroundColor: getUserLevelColor(RoleType.LEVEL_3_USER, false, 'single'),
            borderRadius: '2px',
            border: '1px solid #d9d9d9'
          }}></div>
          <Text style={{ fontSize: '12px' }}>3级用户可预约时间</Text>
        </div>
        {displayFor === 'all' && (
          <div style={{ display: 'flex', alignItems: 'center', gap: 4 }}>
            <div style={{
              width: 16,
              height: 16,
              backgroundColor: getUserLevelColor(RoleType.LEVEL_1_USER, false, 'all'),
              borderRadius: '2px',
              border: '1px solid #d9d9d9'
            }}></div>
            <Text style={{ fontSize: '12px' }}>所有用户模式（当前显示）</Text>
          </div>
        )}
      </div>

      <div
        ref={dragContainerRef}
        style={{ 
          display: 'grid', 
          gridTemplateColumns: '80px repeat(7, 1fr)', 
          gap: '0px',
          backgroundColor: '#f0f0f0',
          border: '1px solid #d9d9d9',
          borderRadius: '6px',
          overflow: 'hidden',
          userSelect: 'none' // 防止文本选择
        }}
        onContextMenu={(e) => e.preventDefault()} // 防止右键菜单
      >
        {/* 时间列标题 */}
        <div style={{ 
          backgroundColor: '#fafafa', 
          padding: '8px 4px', 
          textAlign: 'center',
          borderRight: '1px solid #d9d9d9',
          fontSize: '12px',
          fontWeight: 'bold'
        }}>
          时间
        </div>

        {/* 日期列标题 */}
        {weekDates.map((dateInfo) => {
          const dayStatus = dayStatusMap.get(dateInfo.date);
          const isSelected = selectedDate === dateInfo.date;
          return (
            <div
              key={dateInfo.date}
              style={{
                backgroundColor: isSelected ? '#e6f7ff' : '#fafafa',
                padding: '6px',
                textAlign: 'center',
                border: isSelected ? '2px solid #1890ff' : 'none',
                borderRadius: isSelected ? '4px' : '0',
                boxSizing: 'border-box',
                cursor: readOnly ? 'default' : 'pointer',
                position: 'relative',
                boxShadow: isSelected ? '0 2px 8px rgba(24, 144, 255, 0.2)' : 'none',
                margin: isSelected ? '2px' : '0',
                zIndex: isSelected ? 10 : 1
              }}
              onClick={(e) => {
                e.stopPropagation();
                if (!readOnly) {
                  setSelectedDate(dateInfo.date);
                }
              }}
            >
              <div style={{
                fontSize: '12px',
                color: isSelected ? '#1890ff' : '#666',
                fontWeight: isSelected ? 'bold' : 'normal'
              }}>
                {dateInfo.dayName}
              </div>
              <div style={{ 
                fontSize: '16px', 
                fontWeight: 'bold',
                color: isSelected ? '#1890ff' : 'inherit'
              }}>
                {dateInfo.dayNumber}
                {isSelected && (
                  <div style={{
                    position: 'absolute',
                    top: '2px',
                    right: '2px',
                    width: '6px',
                    height: '6px',
                    backgroundColor: '#1890ff',
                    borderRadius: '50%'
                  }} />
                )}
              </div>
              {dayStatus && (
                <div style={{ marginTop: 4 }}>
                  <Tag 
                    color={dayStatus.scheduleType === ScheduleType.HOLIDAY ? 'red' : 
                          dayStatus.scheduleType === ScheduleType.WORKDAY ? 'blue' : 'purple'}
                  >
                    {dayStatus.scheduleType === ScheduleType.HOLIDAY ? '节假日' : 
                     dayStatus.scheduleType === ScheduleType.WORKDAY ? '工作日' : '周末'}
                  </Tag>
                </div>
              )}
            </div>
          );
        })}

        {/* 时间行 */}
        {Array.from({ length: 24 }, (_, i) => {
          const hour = i; // 从0点开始
          return (
            <React.Fragment key={hour}>
              {/* 时间标签 */}
              <div style={{ 
                backgroundColor: 'white',
                padding: '4px',
                textAlign: 'center',
                borderRight: '1px solid #d9d9d9',
                fontSize: '11px',
                height: '60px',
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'center'
              }}>
                {hour.toString().padStart(2, '0')}:00
              </div>

              {/* 日期列 */}
              {weekDates.map((dateInfo, dateIndex) => {
                const daySlots = allDateSlots.get(dateInfo.date) || [];
                
                // 计算当前格子在预览时间段中的位置
                const currentHourStart = hour * 60;
                const currentHourEnd = (hour + 1) * 60;
                
                const isInPreview = previewData && 
                  dateInfo.date === previewData.startDate && 
                  currentHourStart < previewData.endTime && 
                  currentHourEnd > previewData.startTime;
                
                // 计算预览区域在当前格子中的具体位置
                let previewTop = 0;
                let previewHeight = 100;
                
                if (isInPreview && previewData) {
                  const startInHour = Math.max(previewData.startTime, currentHourStart);
                  const endInHour = Math.min(previewData.endTime, currentHourEnd);
                  
                  previewTop = ((startInHour - currentHourStart) / 60) * 100;
                  previewHeight = ((endInHour - startInHour) / 60) * 100;
                }
                
                return (
                  <div 
                    key={`${dateInfo.date}-${hour}`}
                    style={{ 
                      backgroundColor: 'white',
                      borderLeft: selectedDate === dateInfo.date ? '3px solid #1890ff' : 'none',
                      height: '60px',
                      position: 'relative',
                      cursor: readOnly ? 'default' : 'crosshair',
                      boxSizing: 'border-box',
                      borderRight: selectedDate === dateInfo.date ? '3px solid #1890ff' : 'none',
                      borderBottom: '1px solid #e8e8e8'
                    }}
                    onMouseDown={(e) => {
                      // 如果点击的不是时间段，则清除选中状态
                      if (e.target === e.currentTarget) {
                        setSelectedSlot(null);
                        handleMouseDown(e, dateIndex, hour);
                      }
                    }}
                  >
                    {/* 拖拽预览 */}
                    {isInPreview && previewData && (
                      <div style={{
                        position: 'absolute',
                        top: `${previewTop}%`,
                        height: `${previewHeight}%`,
                        left: '0px',
                        right: '0px',
                        backgroundColor: 'rgba(24, 144, 255, 0.3)',
                        border: '2px dashed #1890ff',
                        borderRadius: '4px',
                        zIndex: 10,
                        display: 'flex',
                        alignItems: 'center',
                        justifyContent: 'center',
                        fontSize: '10px',
                        color: '#1890ff',
                        fontWeight: 'bold',
                        pointerEvents: 'none'
                      }}>
                        {/* 只在开始的格子中显示时间信息 */}
                        {currentHourStart <= previewData.startTime && currentHourEnd > previewData.startTime && (
                          <div style={{ textAlign: 'center', lineHeight: 1 }}>
                            <div>{minutesToTimeString(previewData.startTime).substring(0, 5)}</div>
                            <div style={{ fontSize: '8px' }}>-</div>
                            <div>{minutesToTimeString(previewData.endTime).substring(0, 5)}</div>
                          </div>
                        )}
                      </div>
                    )}

                    {/* 显示时间段 - 优化版本，预过滤时间段 */}
                    {daySlots.filter(slot => {
                      // 预过滤：只处理与当前小时有交集的时间段
                      const currentHourStart = hour * 60;
                      const currentHourEnd = (hour + 1) * 60;
                      return slot.endTime > currentHourStart && slot.startTime < currentHourEnd;
                    }).map((slot) => {
                      const currentHourStart = hour * 60;
                      const currentHourEnd = (hour + 1) * 60;
                      
                      // 计算在当前小时格子中的显示范围
                      const startInHour = Math.max(slot.startTime, currentHourStart);
                      const endInHour = Math.min(slot.endTime, currentHourEnd);
                      
                      const topPercent = ((startInHour - currentHourStart) / 60) * 100;
                      const heightPercent = ((endInHour - startInHour) / 60) * 100;
                      
                      // 只在时间段开始的格子中显示时间文字
                      const showTimeText = currentHourStart <= slot.startTime && currentHourEnd > slot.startTime;

                      return (
                        <Tooltip 
                        placement='right'
                          key={`${slot.id}-${hour}`}
                          title={
                            <div>
                              <div>{minutesToTimeString(slot.startTime).substring(0, 5)} - {minutesToTimeString(slot.endTime).substring(0, 5)}</div>
                              <div>{slot.source === 'specific' ? '自定义预约时段' : '默认配置'}</div>
                              {slot.source === 'specific' && !readOnly && (
                                <div style={{ marginTop: 4, fontSize: '10px', opacity: 0.8 }}>
                                  点击选中 • 双击编辑
                                </div>
                              )}
                              {slot.source === 'default' && !readOnly && (
                                <div style={{ marginTop: 4, fontSize: '10px', opacity: 0.8 }}>
                                  点击转换为自定义预约时段
                                </div>
                              )}
                            </div>
                          }
                        >
                          <div
                            style={{
                              position: 'absolute',
                              top: `${topPercent}%`,
                              height: `${heightPercent}%`,
                              left: '0px',
                              right: '-1px', // 扩展1px覆盖右边框
                              backgroundColor: (() => {
                                const isSelected = selectedSlot?.id === slot.id;
                                return getUserLevelColor(slot.roleType || RoleType.LEVEL_1_USER, isSelected, displayFor);
                              })(),
                              color: '#1890ff', // 文字颜色改为蓝色
                              borderRadius: '0px',
                              padding: showTimeText ? '2px 6px' : '0px',
                              fontSize: '11px',
                              zIndex: selectedSlot?.id === slot.id ? 3 : 2,
                              opacity: slot.source === 'default' ? 0.7 : 1,
                              overflow: 'hidden',
                              display: 'flex',
                              flexDirection: 'column',
                              justifyContent: 'center',
                              alignItems: 'center',
                              // 移除边框，使用阴影表示选中状态
                              boxShadow: selectedSlot?.id === slot.id 
                                ? 'inset 0 0 0 2px #ff4d4f' 
                                : 'none',
                              cursor: slot.source === 'specific' && !readOnly ? 'pointer' : 'default',
                              transition: 'all 0.2s ease', // 添加过渡动画
                              marginBottom: '-1px' // 覆盖底部边框
                            }}
                            onClick={(e) => handleSlotClick(e, slot, dateInfo.date)}
                            onDoubleClick={(e) => handleStartEditDrag(e)}
                            onContextMenu={(e) => handleSlotContextMenu(e, slot, dateInfo.date)}
                          >
                            {/* 顶部调整手柄 */}
                            {selectedSlot?.id === slot.id && slot.source === 'specific' && !readOnly && showTimeText && (
                              <div
                                style={{
                                  position: 'absolute',
                                  top: '-2px',
                                  left: '50%',
                                  transform: 'translateX(-50%)',
                                  width: '20px',
                                  height: '6px',
                                  backgroundColor: '#ff4d4f',
                                  borderRadius: '3px',
                                  cursor: 'n-resize',
                                  zIndex: 4,
                                  display: 'flex',
                                  alignItems: 'center',
                                  justifyContent: 'center'
                                }}
                                onMouseDown={(e) => handleStartResize(e, 'top')}
                              >
                                <div style={{ 
                                  width: '12px', 
                                  height: '2px', 
                                  backgroundColor: 'white', 
                                  borderRadius: '1px' 
                                }} />
                              </div>
                            )}
                            
                            {/* 底部调整手柄 */}
                            {selectedSlot?.id === slot.id && slot.source === 'specific' && !readOnly && (currentHourEnd >= slot.endTime) && (
                              <div
                                style={{
                                  position: 'absolute',
                                  bottom: '-2px',
                                  left: '50%',
                                  transform: 'translateX(-50%)',
                                  width: '20px',
                                  height: '6px',
                                  backgroundColor: '#ff4d4f',
                                  borderRadius: '3px',
                                  cursor: 's-resize',
                                  zIndex: 4,
                                  display: 'flex',
                                  alignItems: 'center',
                                  justifyContent: 'center'
                                }}
                                onMouseDown={(e) => handleStartResize(e, 'bottom')}
                              >
                                <div style={{ 
                                  width: '12px', 
                                  height: '2px', 
                                  backgroundColor: 'white', 
                                  borderRadius: '1px' 
                                }} />
                              </div>
                            )}

                            {showTimeText && (
                              <>
                                <div style={{ fontSize: '10px', fontWeight: 'bold', lineHeight: 1 }}>
                                  {minutesToTimeString(slot.startTime).substring(0, 5)}
                                </div>
                                <div style={{ fontSize: '9px', lineHeight: 1, opacity: 0.9 }}>
                                  {minutesToTimeString(slot.endTime).substring(0, 5)}
                                </div>
                              </>
                            )}
                          </div>
                        </Tooltip>
                      );
                    })}
                  </div>
                );
              })}
            </React.Fragment>
          );
        })}
      </div>
      
      {/* 右键菜单 */}
      {contextMenu.visible && (
        <>
          <div 
            style={{
              position: 'fixed',
              top: 0,
              left: 0,
              right: 0,
              bottom: 0,
              zIndex: 999
            }}
            onClick={handleCloseContextMenu}
          />
          <div
            style={{
              position: 'fixed',
              top: contextMenu.y,
              left: contextMenu.x,
              backgroundColor: 'white',
              border: '1px solid #d9d9d9',
              borderRadius: '6px',
              boxShadow: '0 4px 12px rgba(0, 0, 0, 0.15)',
              zIndex: 1000,
              minWidth: '120px'
            }}
          >
            <div
              style={{
                padding: '8px 16px',
                cursor: 'pointer',
                borderBottom: '1px solid #f0f0f0'
              }}
              onClick={() => {
                if (contextMenu.slot) {
                  setSelectedSlot(contextMenu.slot);
                  setSelectedDate(contextMenu.slot.date);
                  handleStartEditDrag({ preventDefault: () => {}, stopPropagation: () => {} } as React.MouseEvent);
                }
                handleCloseContextMenu();
              }}
            >
              ✏️ 编辑时间段
            </div>
            <div
              style={{
                padding: '8px 16px',
                cursor: 'pointer',
                color: '#ff4d4f'
              }}
              onClick={() => {
                if (contextMenu.slot) {
                  handleDeleteSlot(contextMenu.slot);
                }
              }}
            >
              🗑️ 删除时间段
            </div>
          </div>
        </>
      )}
      


      {/* 拖拽时的鼠标跟随指示器 */}
      {isDragging && mousePosition && dragContainerRef.current && (
        <div
          style={{
            position: 'fixed',
            left: mousePosition.x + 15,
            top: mousePosition.y - 35,
            backgroundColor: 'rgba(24, 144, 255, 0.95)',
            color: 'white',
            padding: '6px 12px',
            borderRadius: '6px',
            fontSize: '13px',
            fontWeight: '500',
            pointerEvents: 'none',
            zIndex: 9999,
            whiteSpace: 'nowrap',
            boxShadow: '0 4px 12px rgba(0,0,0,0.2)',
            border: '1px solid rgba(255,255,255,0.2)',
            backdropFilter: 'blur(4px)'
          }}
        >
          {previewData ? (
            <>
              <span style={{ opacity: 0.8 }}>⏰ </span>
              {`${minutesToTimeString(previewData.startTime).substring(0, 5)} - ${minutesToTimeString(previewData.endTime).substring(0, 5)}`}
              <span style={{ opacity: 0.7, marginLeft: 8, fontSize: '11px' }}>
                ({Math.round((previewData.endTime - previewData.startTime) / 60 * 10) / 10}h)
              </span>
            </>
          ) : (
            <>
              <span style={{ opacity: 0.8 }}>🖱️ </span>
              拖拽中...
            </>
          )}
        </div>
      )}
    </Card>
  );
};

export default React.memo(CalendarView); 